from PyQt4.QtCore import QObject
from PyQt4.QtCore import SIGNAL

import config

from game.boardModel import BoardModel

from views.localGame.gameView import LocalGameView
from views.onlineGame.gameView import OnlineGameView

from views.localGame.newGame import NewGameView
from views.onlineGame.login import LoginView
from views.welcome import WelcomeView
from views.widgets.gameMessage import GameMessage
from views.onlineGame.resetPasswordView import ResetPasswordView
from views.onlineGame.partner import PartnerView
from views.onlineGame.signUpView import SignUpView

from network.gameDriver import GameDriver
from network.userDriver import UserDriver

from autoplayer.player import AutoPlayer


class Navigator(QObject):
    def __init__(self, parent=None):
        super(Navigator, self).__init__(parent)
        # view
        self.welcomeView = WelcomeView()
        self.newAutoGameView = NewGameView()
        self.loginView = LoginView()
        self.localGameView = LocalGameView()
        self.onlineGameView = OnlineGameView()
        self.resetPasswordView = ResetPasswordView()
        self.partnerView = PartnerView()
        self.signUpView = SignUpView()
        # model
        self.localGameModel = BoardModel()
        self.onlineGameModel = BoardModel()
        self.localGameView.boardView.setModel(self.localGameModel)
        self.onlineGameView.boardView.setModel(self.onlineGameModel)
        # driver
        self.userDriver = UserDriver()
        self.gameDriver = GameDriver()
        # auto player
        self.auto_game = False
        self.auto_level = 0
        self.auto_role = config.ROLES.vacant
        self.autoplayer = AutoPlayer()
        # connect
        self.initConnect()

    def initConnect(self):
        # welcome
        self.connect(self.welcomeView.manMachineGameButton, SIGNAL('clicked()'), self.man_machine_game_clicked)
        self.connect(self.welcomeView.onlineGameButton, SIGNAL('clicked()'), self.online_game_clicked)
        self.connect(self.welcomeView.twoMenGameButton, SIGNAL('clicked()'), self.two_men_game_accepted)
        # new local game
        self.connect(self.newAutoGameView, SIGNAL('accepted(int, int)'), self.auto_game_accepted)
        self.connect(self.newAutoGameView.buttonBox, SIGNAL('rejected()'), self.auto_game_rejected)
        # new online game
        self.connect(self.loginView.returnButton, SIGNAL('clicked()'), self.online_game_rejected)
        # local game view
        self.connect(self.localGameModel, SIGNAL('gameOver(int)'), self.end_local_game)
        self.connect(self.localGameModel, SIGNAL('boardChanged()'),  self.localGameView.update)
        self.connect(self.localGameView.boardView, SIGNAL('new_step(int, int)'), self.local_game_new_step)
        self.connect(self.localGameView.retractButton, SIGNAL('clicked()'), self.local_game_retract)
        self.connect(self.localGameView.newGameButton, SIGNAL('clicked()'), self.local_game_restart)
        self.connect(self.localGameView.returnButton, SIGNAL('clicked()'), self.local_game_return_clicked)
        self.connect(self.localGameView.remindButton, SIGNAL('clicked()'), self.local_game_remind)
        # online game login
        self.connect(self.loginView.loginButton, SIGNAL('clicked()'), self.login_clicked)
        self.connect(self.loginView.signupButton, SIGNAL('clicked()'), self.sign_up_clicked)
        self.connect(self.loginView.resetPassswordButton, SIGNAL('clicked()'), self.reset_password_clicked)
        self.connect(self.userDriver, SIGNAL('login_succeed()'), self.login_succeed)
        self.connect(self.userDriver, SIGNAL('login_failed()'), self.login_failed)
        # online game sign up
        self.connect(self.signUpView.buttonBox, SIGNAL('accepted()'), self.sign_up_accept)
        self.connect(self.signUpView.buttonBox, SIGNAL('rejected()'), self.sign_up_return)
        self.connect(self.userDriver, SIGNAL('sign_up_succeed()'), self.sign_up_success)
        self.connect(self.userDriver, SIGNAL('sign_up_failed()'), self.sign_up_failed)
        # online game reset password
        self.connect(self.resetPasswordView.buttonBox, SIGNAL('accepted()'), self.reset_password_accept)
        self.connect(self.resetPasswordView.buttonBox, SIGNAL('rejected()'), self.reset_password_reject)
        self.connect(self.userDriver, SIGNAL('reset_password_result(int)'), self.reset_password_result)
        # online game partner
        self.connect(self.partnerView.readyButton, SIGNAL('clicked()'), self.set_ready)
        self.connect(self.partnerView.returnButton, SIGNAL('clicked()'), self.partner_return)
        self.connect(self.partnerView.changeButton, SIGNAL('clicked()'), self.change_clicked)
        self.connect(self.userDriver, SIGNAL('partner_changed()'), self.change_partner)
        self.connect(self.userDriver, SIGNAL('partner_ready(int)'), self.partner_ready)
        self.connect(self.userDriver, SIGNAL('game_start(int)'), self.game_start)
        # online game
        self.connect(self.onlineGameView.retractButton, SIGNAL('clicked()'), self.ask_retract)
        self.connect(self.onlineGameView.resignButton, SIGNAL('clicked()'), self.send_resign)
        self.connect(self.onlineGameView.peaceButton, SIGNAL('clicked()'), self.ask_peace)
        self.connect(self.gameDriver, SIGNAL('new_step(int, int)'), self.partner_new_step)
        self.connect(self.gameDriver, SIGNAL('partner_resign()'), self.partner_resign)
        self.connect(self.gameDriver, SIGNAL('partner_peace_ask()'), self.partner_peace_ask)
        self.connect(self.gameDriver, SIGNAL('partner_retract_ask()'), self.partner_retract_ask)
        self.connect(self.gameDriver, SIGNAL('peace_answer(int)'), self.peace_answer)
        self.connect(self.gameDriver, SIGNAL('retract_answer(int)'), self.retract_answer)
        self.connect(self.onlineGameModel, SIGNAL('boardChanged()'), self.onlineGameView.update)
        self.connect(self.onlineGameModel, SIGNAL('gameOver(int)'), self.end_online_game)
        self.connect(self.onlineGameView.boardView, SIGNAL('new_step(int, int)'), self.send_new_step)

    def start(self):
        self.welcomeView.show()

    def man_machine_game_clicked(self):
        self.welcomeView.hide()
        self.newAutoGameView.show()

    def online_game_clicked(self):
        self.welcomeView.hide()
        self.loginView.show()

    def two_men_game_accepted(self):
        self.auto_game = False
        self.welcomeView.hide()
        self.localGameModel.new_game()
        self.localGameView.show()

    def auto_game_accepted(self, role=config.ROLES.vacant, level=0):
        # set autoplayer
        self.autoplayer.setup(self.localGameModel, role)
        self.auto_role = role
        self.auto_game = True
        self.auto_level = level
        # set model
        self.newAutoGameView.hide()
        self.localGameModel.new_game()
        self.localGameView.show()
        # make first move
        if role == config.ROLES.firsthand:
            self.localGameModel.new_step(7, 7)

    def auto_game_rejected(self):
        self.newAutoGameView.hide()
        self.welcomeView.show()

    def online_game_rejected(self):
        self.loginView.hide()
        self.welcomeView.show()

    def end_local_game(self, result):
        if result == config.ROLES.firsthand:
            msg = 'Black Player Wins'
        elif result == config.ROLES.secondhand:
            msg = 'White Player Wins'
        elif result == config.ROLES.vacant:
            msg = 'Drawn Game'
        self.localGameModel.end_game()
        GameMessage.information(self.localGameView, 'GameOver', msg, GameMessage.Ok)

    def local_game_return_clicked(self):
        self.localGameView.hide()
        self.welcomeView.show()

    def local_game_new_step(self, x, y):
        # two men game
        if not self.auto_game:
            self.localGameModel.new_step(x, y)
            return
        # auto game
        if self.localGameModel.get_role() == self.auto_role:
            return
        self.localGameModel.new_step(x, y)
        auto_x, auto_y = self.autoplayer.react()
        self.localGameModel.new_step(auto_x, auto_y)

    def local_game_retract(self):
        if not self.auto_game:
            self.localGameModel.retract()
        if self.localGameModel.get_role() == self.auto_role:
            return
        elif self.auto_role == config.ROLES.firsthand:
            if self.localGameModel.history.__len__() <= 1:
                return
        else:
            self.localGameModel.retract()
            self.localGameModel.retract()

    def local_game_restart(self):
        self.localGameModel.new_game()
        if self.auto_game:
            self.auto_game_accepted(self.auto_role, self.auto_role)

    def local_game_remind(self):
        role = self.localGameModel.get_role()
        self.autoplayer.setup(self.localGameModel, role)
        x, y = self.autoplayer.react()
        self.local_game_new_step(x, y)

    def reset_password_clicked(self):
        self.loginView.hide()
        self.resetPasswordView.show()

    def reset_password_accept(self):
        # vaildate
        if self.resetPasswordView.newPasswordInput.edit.text() != self.resetPasswordView.confirmPasswordInput.edit.text():
            return
        username = self.resetPasswordView.nameInput.edit.text()
        password = self.resetPasswordView.oldPasswordInput.edit.text()
        newPassword = self.resetPasswordView.newPasswordInput.edit.text()
        self.userDriver.resetPassword(username, password, newPassword)

    def login_clicked(self):
        username = self.loginView.nameInput.edit.text()
        password = self.loginView.passwordInput.edit.text()
        self.userDriver.login(username, password)

    def reset_password_reject(self):
        self.resetPasswordView.hide()
        self.loginView.show()

    def reset_password_result(self, result):
        if result == 0:
            GameMessage.information(self.loginView, 'Reset Password', 'Reset Successful', GameMessage.Ok)
            self.resetPasswordView.hide()
            self.loginView.show()
        elif result == 1:
            GameMessage.information(self.resetPasswordView, 'Reset Password', 'Invalid Password', GameMessage.Ok)

    def login_succeed(self):
        # self.userDriver.exec_()
        self.loginView.hide()
        username = self.userDriver.self_name
        success = self.userDriver.self_success
        failure = self.userDriver.self_failure
        score = self.userDriver.self_score
        self.partnerView.setSelfData(username, success, failure, score)
        self.partnerView.show()
        self.userDriver.startTimer(config.interval)

    def login_failed(self):
        GameMessage.information(self.loginView, 'Login', 'Login Failed', GameMessage.Ok)

    def sign_up_clicked(self):
        self.loginView.hide()
        self.signUpView.show()

    def sign_up_accept(self):
        # print('sign up accept')
        username = self.signUpView.nameInput.edit.text()
        password = self.signUpView.passwordInput.edit.text()
        confirm_password = self.signUpView.confirmPasswordInput.edit.text()
        email = self.signUpView.emailInput.edit.text()
        if password != confirm_password:
            GameMessage.information(self.signUpView, 'Error', 'Passwords does not match', GameMessage.Ok)
            return
        # print('signing up' + username)
        self.userDriver.signUp(username, password, email)


    def sign_up_return(self):
        self.signUpView.hide()
        self.loginView.show()

    def sign_up_failed(self):
        GameMessage.information(self.signUpView, 'Sign Up', 'Sign Up Failed, Illegal Username', GameMessage.Ok)

    def sign_up_success(self):
        GameMessage.information(self.loginView, 'Sign Up', 'Sign Up Succeed', GameMessage.Ok)
        self.signUpView.hide()
        self.loginView.show()

    def partner_return(self):
        self.partnerView.hide()
        self.loginView.show()
        self.userDriver.logout()

    def set_ready(self):
        if not self.partnerView.ready:
            self.partnerView.ready = True
            self.partnerView.selfWidget.setReady(True)
            self.userDriver.ready(True)
        else:
            self.partnerView.ready = False
            self.partnerView.selfWidget.setReady(False)
            self.userDriver.ready(False)

    def debug_set_ready(self):
        if not self.partnerView.ready:
            self.partnerView.ready = True
            self.partnerView.selfWidget.setReady(True)
        else:
            self.partnerView.ready = False
            self.partnerView.selfWidget.setReady(False)

    def change_partner(self):
        name = self.userDriver.partner_name
        success = self.userDriver.partner_success
        failure = self.userDriver.partner_failure
        score = self.userDriver.partner_score
        ready = self.userDriver.partner_ready
        print('change partner', self.userDriver.self_name, name)
        self.partnerView.setPartnerData(name, success, failure, score, ready)
        self.userDriver.online = True

    def partner_ready(self, ready):
        self.partnerView.partnerWidget.setReady(ready)
        self.userDriver.online = True

    def start_game(self):
        self.partnerView.hide()
        self.onlineGameView.show()

    def change_clicked(self):
        self.userDriver.change()

    def game_start(self, role):
        self.gameDriver.role = role
        self.partnerView.hide()
        if role == config.ROLES.firsthand:
            GameMessage.information(self.onlineGameView, 'Game Start', 'You move first', GameMessage.Ok)
        elif role == config.ROLES.secondhand:
            GameMessage.information(self.onlineGameView, 'Game Start', 'Your partner moves first', GameMessage.Ok)
        self.onlineGameView.show()
        self.gameDriver.self_name = self.userDriver.self_name
        self.gameDriver.partner_name = self.userDriver.partner_name
        #
        self.onlineGameView.setWindowTitle('Game' + self.userDriver.self_name)
        # start online game
        self.onlineGameModel.new_game()
        self.gameDriver.online = True
        self.gameDriver.startTimer(config.interval)
        # self.userDriver.online = False

    def ask_retract(self):
        title = 'Retract'
        msg = 'Are you sure to ask for retract?'
        answer = GameMessage.information(self.onlineGameView, title, msg, GameMessage.Ok | GameMessage.Cancel)
        if answer == GameMessage.Ok:
            self.gameDriver.retract_ask()

    def send_resign(self):
        title = 'resign'
        msg = 'Are you sure to resign?'
        answer = GameMessage.information(self.onlineGameView, title, msg, GameMessage.Ok | GameMessage.Cancel)
        if answer == GameMessage.Ok:
            self.gameDriver.resign()
            self.onlineGameView.hide()
            self.partnerView.show()


    def ask_peace(self):
        title = 'Peace'
        msg = 'Are you sure to ask for peace?'
        answer = GameMessage.information(self.onlineGameView, title, msg, GameMessage.Ok | GameMessage.Cancel)
        if answer == GameMessage.Ok:
            self.gameDriver.peace_ask()
            self.onlineGameView.hide()
            self.partnerView.show()

    def partner_resign(self):
        title = 'Win'
        msg = 'Your partner resigned!'
        answer = GameMessage.information(self.onlineGameView, title, msg, GameMessage.Ok)
        self.onlineGameView.hide()
        self.partnerView.show()
        # self.gameDriver.online = False

    def partner_peace_ask(self):
        title = 'Peace'
        msg = 'Your partner is asking for peace.'
        answer = GameMessage.information(self.onlineGameView, title, msg, GameMessage.Ok | GameMessage.Cancel)
        if answer == GameMessage.Ok:
            self.gameDriver.peace_answer(True)
            self.onlineGameView.hide()
            self.partnerView.show()
        else:
            self.gameDriver.peace_answer(False)
        self.gameDriver.online = True

    def partner_retract_ask(self):
        title = 'Retract'
        msg = 'Your partner is asking for retract.'
        answer = GameMessage.information(self.onlineGameView, title, msg, GameMessage.Ok | GameMessage.Cancel)
        if answer == GameMessage.Ok:
            self.gameDriver.retract_answer(True)
            self.onlineGameModel.retract()
        else:
            self.gameDriver.retract_answer(False)
        self.gameDriver.online = True

    def peace_answer(self, answer):
        title = 'Peace'
        if answer == 1:
            msg = 'Partner agreed'
            self.onlineGameModel.hide()
            GameMessage.information(self.partnerView, title, msg, GameMessage.Ok)
            self.partnerView.show()
        else:
            msg = 'Partner disagreed'
            GameMessage.information(self.onlineGameView, title, msg, GameMessage.Ok)
        self.gamedriver.online = True

    def retract_answer(self, answer):
        title = 'Retract'
        if answer == 1:
            msg = 'Partner agreed'
            self.onlineGameModel.retract()
        else:
            msg = 'Partner disagreed'
        GameMessage.information(self.onlineGameView, title, msg, GameMessage.Ok)
        self.gamedriver.online = True

    def send_new_step(self, x, y):
        role = self.gameDriver.role
        if role == self.onlineGameModel.get_role():
            self.onlineGameModel.new_step(x, y)
            self.gameDriver.new_step(x, y)
            self.gameDriver.online = True

    def partner_new_step(self, x, y):
        self.onlineGameModel.new_step(x, y)
        self.gameDriver.online = True

    def end_online_game(self, result):
        self.onlineGameModel.end_game()
        role = self.gameDriver.role
        # remind
        title = 'Game Over'
        if role != result:
            msg = 'You Lose!'
            self.gameDriver.resign()
            GameMessage.information(self.partnerView, title, msg, GameMessage.Ok)
        # window
        self.onlineGameView.hide()
        self.partnerView.show()
        # todo: reset user driver



